package com.keqiang.chart.impl.pie.impl.pseudo3d

import android.view.MotionEvent
import com.keqiang.chart.impl.pie.Base3DTouchHandler
import com.keqiang.chart.impl.pie.impl.normal.PieEntity
import com.keqiang.chart.utils.ObjectPool
import com.keqiang.chart.utils.to360Range
import com.keqiang.chart.utils.toRadian
import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sqrt

/**
 * 饼状图触摸事件处理
 *
 * @author Created by wanggaowan on 2022/8/4 16:02
 */
open class PieChart3DTouchHandler(chart: PieChart3D) : Base3DTouchHandler<PieChart3D, PieEntity>(chart) {

    override fun findClickData(e: MotionEvent): PieEntity? {
        val dataList = chart.data
        if (dataList.isNullOrEmpty()) {
            return null
        }

        val angleForPoint = getAngleForPoint(e.x, e.y)
        var entity: PieEntity? = null
        val path = ObjectPool.obtainPath()
        val pathMeasure = ObjectPool.obtainPathMeasure()
        val floatArray = ObjectPool.obtainFloatArray()
        val (centerX, centerY) = chart.getCenter()

        for (index in dataList.indices) {
            val data = dataList[index]
            val radius = data.drawRadius + sqrt(data.offsetDx.pow(2) + data.offsetDy.pow(2))
            val radiusShort = radius * cos(chart.getDrawFlipAngle().toRadian)

            if (e.x < centerX - radius || e.x > centerX + radius) {
                continue
            }

            if (e.y < centerY - radiusShort || e.y > centerY + radiusShort + chart.getDrawHeight()) {
                continue
            }

            if (chart.innerRadius > 0) {
                val innerRadius =
                    chart.innerRadius + sqrt(data.offsetDx.pow(2) + data.offsetDy.pow(2))
                val innerRadiusShort = innerRadius * cos(chart.getDrawFlipAngle().toRadian)
                val tx: Double = (e.x - centerX).toDouble()
                val ty: Double = (e.y - centerY).toDouble()
                val length = sqrt(tx * tx + ty * ty)
                if (length < innerRadiusShort - chart.getDrawHeight()) {
                    continue
                }
            }

            var startAngle = data.drawStartAngle.to360Range
            var endAngle = (startAngle + data.drawSweepAngle).to360Range

            // 此时圆心为圆柱顶部椭圆圆心
            path.reset()
            path.arcTo(centerX - radius, centerY - radiusShort,
                centerX + radius, centerY + radiusShort, startAngle, data.drawSweepAngle, false)
            pathMeasure.setPath(path, false)
            if ((startAngle in 0f..180f || endAngle in 0f..180f) && e.y > centerY + radiusShort) {
                // 点击了3D饼状图上下两个椭圆中间区域
                val startX: Float
                val endX: Float
                if (startAngle <= 180f) {
                    pathMeasure.getPosTan(0f, floatArray, null)
                    endX = floatArray[0]
                    startX = if (endAngle >= 180f) {
                        centerX - radius
                    } else {
                        pathMeasure.getPosTan(pathMeasure.length, floatArray, null)
                        floatArray[0]
                    }
                } else {
                    endX = centerX + radius
                    pathMeasure.getPosTan(pathMeasure.length, floatArray, null)
                    startX = floatArray[0]
                }

                if (e.x in startX..endX) {
                    entity = data
                    break
                }
            } else {
                pathMeasure.getPosTan(0f, floatArray, null)
                startAngle = getAngleForPoint(floatArray[0], floatArray[1])
                pathMeasure.getPosTan(pathMeasure.length, floatArray, null)
                endAngle = getAngleForPoint(floatArray[0], floatArray[1])

                if (startAngle > endAngle) {
                    if (angleForPoint >= startAngle && angleForPoint < 360) {
                        entity = data
                        break
                    } else if (angleForPoint in 0f..endAngle) {
                        entity = data
                        break
                    }
                } else if (angleForPoint in startAngle..endAngle) {
                    entity = data
                    break
                }
            }
        }

        ObjectPool.recyclePath(path)
        ObjectPool.recyclePathMeasure(pathMeasure)
        ObjectPool.recycleFloatArray(floatArray)
        return entity
    }
}